use axum::http::StatusCode;
use serde::Deserialize;

#[derive(Clone, Deserialize, Debug)]
pub struct UploadConfig {
    #[serde(default)]
    pub(crate) root: String,
    #[serde(default)]
    pub(crate) max_body_length: u64,
    #[serde(default)]
    pub(crate) date: String,
    #[serde(default)]
    pub(crate) upload_prefix: String,
    #[serde(default)]
    pub(crate) raw_prefix: String,
    #[serde(default)]
    pub(crate) url_prefix: String,
}

impl Default for UploadConfig {
    fn default() -> Self {
        Self::from_env()
    }
}

impl UploadConfig {
    pub fn from_env() -> Self {
        let mut cnf: Self = config::Config::builder()
            .add_source(
                config::Environment::default(), // .prefix("upload")
                                                // .separator("_"),
            )
            .build()
            .unwrap()
            .try_deserialize()
            .unwrap();
        cnf.root = if cnf.root.is_empty() {
            "uploads".to_string()
        } else {
            cnf.root
        };
        cnf.upload_prefix = if cnf.upload_prefix.is_empty() {
            "upload".to_string()
        } else {
            cnf.upload_prefix
        };
        cnf.raw_prefix = if cnf.raw_prefix.is_empty() {
            "raw".to_string()
        } else {
            cnf.raw_prefix
        };
        cnf.max_body_length = if cnf.max_body_length <= 0 {
            1024 * 1024 * 20
        } else {
            cnf.max_body_length
        };
        Self {
            root: cnf.root.trim_matches('/').to_string(),
            date: cnf.date.trim_matches('/').to_string(),
            max_body_length: cnf.max_body_length,
            upload_prefix: cnf.upload_prefix.trim_matches('/').to_string(),
            raw_prefix: cnf.raw_prefix.trim_matches('/').to_string(),
            url_prefix: format!("/{}", cnf.url_prefix.trim_matches('/')),
        }
    }

    pub fn check_body_length(
        &self,
        content_length: Option<u64>,
    ) -> Result<(), (StatusCode, String)> {
        if let Some(l) = content_length {
            if l > self.max_body_length {
                return Err((
                    StatusCode::PAYLOAD_TOO_LARGE,
                    format!("max body size is {}", self.max_body_length),
                ));
            }
        };
        Ok(())
    }
}
